
<!DOCTYPE HTML>
<html lang="zh-hans" >
    <head>
        <meta charset="UTF-8">
        <title>14 数值 · C++导览 第二版 简体中文版</title>
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="description" content="">
        <meta name="generator" content="HonKit 5.1.1">
        <meta name="author" content="Windsting">
        
        
    
    <link rel="stylesheet" href="gitbook/style.css">

    
            
                
                <link rel="stylesheet" href="gitbook/@dogatana/honkit-plugin-page-toc-button/plugin.css">
                
            
                
                <link rel="stylesheet" href="gitbook/@dogatana/honkit-plugin-back-to-top-button/plugin.css">
                
            
                
                <link rel="stylesheet" href="gitbook/gitbook-plugin-forkmegithub/plugin.css">
                
            
                
                <link rel="stylesheet" href="gitbook/@honkit/honkit-plugin-highlight/website.css">
                
            
                
                <link rel="stylesheet" href="gitbook/gitbook-plugin-search/search.css">
                
            
                
                <link rel="stylesheet" href="gitbook/gitbook-plugin-fontsettings/website.css">
                
            
        

    

    
        
        <link rel="stylesheet" href="styles/website.css">
        
    
        
    
        
    
        
    
        
    
        
    

        
    
    
    <meta name="HandheldFriendly" content="true"/>
    <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black">
    <link rel="apple-touch-icon-precomposed" sizes="152x152" href="gitbook/images/apple-touch-icon-precomposed-152.png">
    <link rel="shortcut icon" href="gitbook/images/favicon.ico" type="image/x-icon">

    
    <link rel="next" href="ch15.html" />
    
    
    <link rel="prev" href="ch13.html" />
    

    </head>
    <body>
        
<div class="book honkit-cloak">
    <div class="book-summary">
        
            
<div id="book-search-input" role="search">
    <input type="text" placeholder="输入并搜索" />
</div>

            
                <nav role="navigation">
                


<ul class="summary">
    
    
    
        
        <li>
            <a href="https://github.com/windsting/a-tour-of-cpp-2nd-cn" target="_blank" class="custom-link">Github Link</a>
        </li>
    
    

    
    <li class="divider"></li>
    

    
        
        
    
        <li class="chapter " data-level="1.1" data-path="translation_note.html">
            
                <a href="translation_note.html">
            
                    
                    译者言
            
                </a>
            

            
        </li>
    
        <li class="chapter " data-level="1.2" data-path="./">
            
                <a href="./">
            
                    
                    前言
            
                </a>
            

            
        </li>
    
        <li class="chapter " data-level="1.3" data-path="ch01.html">
            
                <a href="ch01.html">
            
                    
                    1 基础知识
            
                </a>
            

            
        </li>
    
        <li class="chapter " data-level="1.4" data-path="ch02.html">
            
                <a href="ch02.html">
            
                    
                    2 用户定义类型
            
                </a>
            

            
        </li>
    
        <li class="chapter " data-level="1.5" data-path="ch03.html">
            
                <a href="ch03.html">
            
                    
                    3 模块化
            
                </a>
            

            
        </li>
    
        <li class="chapter " data-level="1.6" data-path="ch04.html">
            
                <a href="ch04.html">
            
                    
                    4 类
            
                </a>
            

            
        </li>
    
        <li class="chapter " data-level="1.7" data-path="ch05.html">
            
                <a href="ch05.html">
            
                    
                    5 基本操作
            
                </a>
            

            
        </li>
    
        <li class="chapter " data-level="1.8" data-path="ch06.html">
            
                <a href="ch06.html">
            
                    
                    6 模板
            
                </a>
            

            
        </li>
    
        <li class="chapter " data-level="1.9" data-path="ch07.html">
            
                <a href="ch07.html">
            
                    
                    7 概束和泛型编程
            
                </a>
            

            
        </li>
    
        <li class="chapter " data-level="1.10" data-path="ch08.html">
            
                <a href="ch08.html">
            
                    
                    8 标准库概览
            
                </a>
            

            
        </li>
    
        <li class="chapter " data-level="1.11" data-path="ch09.html">
            
                <a href="ch09.html">
            
                    
                    9 字符串和正则表达式
            
                </a>
            

            
        </li>
    
        <li class="chapter " data-level="1.12" data-path="ch10.html">
            
                <a href="ch10.html">
            
                    
                    10 输入输出
            
                </a>
            

            
        </li>
    
        <li class="chapter " data-level="1.13" data-path="ch11.html">
            
                <a href="ch11.html">
            
                    
                    11 容器
            
                </a>
            

            
        </li>
    
        <li class="chapter " data-level="1.14" data-path="ch12.html">
            
                <a href="ch12.html">
            
                    
                    12 算法
            
                </a>
            

            
        </li>
    
        <li class="chapter " data-level="1.15" data-path="ch13.html">
            
                <a href="ch13.html">
            
                    
                    13 实用功能
            
                </a>
            

            
        </li>
    
        <li class="chapter active" data-level="1.16" data-path="ch14.html">
            
                <a href="ch14.html">
            
                    
                    14 数值
            
                </a>
            

            
        </li>
    
        <li class="chapter " data-level="1.17" data-path="ch15.html">
            
                <a href="ch15.html">
            
                    
                    15 并发
            
                </a>
            

            
        </li>
    
        <li class="chapter " data-level="1.18" data-path="ch16.html">
            
                <a href="ch16.html">
            
                    
                    16 历史及兼容性
            
                </a>
            

            
        </li>
    
        <li class="chapter " data-level="1.19" data-path="idx.html">
            
                <a href="idx.html">
            
                    
                    索引
            
                </a>
            

            
        </li>
    

    

    <li class="divider"></li>

    <li>
        <a href="https://github.com/honkit/honkit" target="blank" class="gitbook-link">
            本书使用 HonKit 发布
        </a>
    </li>
</ul>


                </nav>
            
        
    </div>

    <div class="book-body">
        
            <div class="body-inner">
                
                    

<div class="book-header" role="navigation">
    

    <!-- Title -->
    <h1>
        <i class="fa fa-circle-o-notch fa-spin"></i>
        <a href="." >14 数值</a>
    </h1>
</div>




                    <div class="page-wrapper" tabindex="-1" role="main">
                        <div class="page-inner">
                            
<div id="book-search-results">
    <div class="search-noresults">
    
                                <section class="normal markdown-section">
                                

    
        
                                <p><a class="en-page-number" id="187"></a></p>
<div class="chapter-number"><p class="chapter-number">14</p></div>

<h1 id="umerics">数值 </h1>
<blockquote>
<p>计算的目的在于洞悉事物，而非数字本身。</p>
<p><span title="这段话刊载于 R. W. Hamming 的著作《Numerical methods for scientists and engineers》，此书未见中文版。">—— 理查德·卫斯里·汉明</span><sup><a href="#fn_1" id="reffn_1">1</a></sup></p>
<p>……但对学生而言，</p>
<p>数据往往是开启洞察力的最佳途径。</p>
<p><span title="Anthony Ralston 简介见 https://history.computer.org/pioneers/ralston.html">—— Anthony Ralston</span><sup><a href="#fn_2" id="reffn_2">2</a></sup></p>
</blockquote>
<h2 id="14.1">14.1 导言 </h2>
<p>C++在设计之初并未做数值计算方面着重考虑过。
但数值计算却常穿插于其它业务——比如数据库访问、网络系统、仪器控制、图形学、
仿真及金融分析等等——因此对于较大系统中的计算部分，C++就成了香饽饽。
此外，数值方法早已远非遍历浮点数向量这样简单的任务。
在参与计算的数据结构日益复杂之处，C++的威力变得举足轻重。
这导致C++广泛用于科学、工程、金融及其它涉及复杂计算的领域。
因此，此类计算的辅助构件和技术则应运而生。
本章讲述标准库中有关数值计算的部分。</p>
<p><a class="en-page-number" id="188"></a></p>
<h2 id="14.2">14.2 数学函数 </h2>
<p>头文件<code>&lt;cmath&gt;</code>提供了<em>标准数学函数（standard mathematical functions）</em>，
例如针对参数类型<code>float</code>、<code>double</code>以及<code>long double</code>的
<code>sqrt()</code>、<code>log()</code>和<code>sin()</code>等：</p>
<table style="width:90%;margin-left:auto;margin-right:auto;">
    <tbody>
        <tr>
            <th colspan="2" style="text-align: center">
                <strong>标准数学函数</strong><br>
            </th>
        </tr>
        <tr>
            <td style="width:10%"><code>abs(x)</code></td>
            <td>绝对值</td>
        </tr>
        <tr>
            <td><code>ceil(x)</code></td>
            <td>&gt;=<code>x</code>的最小整数</td>
        </tr>
        <tr>
            <td><code>floor(x)</code></td>
            <td>&lt;=<code>x</code>的最大整数</td>
        </tr>
        <tr>
            <td><code>sqrt(x)</code></td>
            <td>平方根；<code>x</code>不能是负数</td>
        </tr>
        <tr>
            <td><code>cos(x)</code></td>
            <td>余弦函数</td>
        </tr>
        <tr>
            <td><code>sin(x)</code></td>
            <td>正弦函数</td>
        </tr>
        <tr>
            <td><code>tan(x)</code></td>
            <td>正切函数</td>
        </tr>
        <tr>
            <td><code>acos(x)</code></td>
            <td>反余弦函数；结果不为负</td>
        </tr>
        <tr>
            <td><code>asin(x)</code></td>
            <td>反正弦函数；返回最靠近0的结果</td>
        </tr>
        <tr>
            <td><code>atan(x)</code></td>
            <td>反正切函数</td>
        </tr>
        <tr>
            <td><code>sinh(x)</code></td>
            <td>双曲正弦函数</td>
        </tr>
        <tr>
            <td><code>cosh(x)</code></td>
            <td>双曲余弦函数</td>
        </tr>
        <tr>
            <td><code>tanh(x)</code></td>
            <td>双曲正切函数</td>
        </tr>
        <tr>
            <td><code>exp(x)</code></td>
            <td>e(自然常数)的x次幂</td>
        </tr>
        <tr>
            <td><code>log(x)</code></td>
            <td>自然对数，以e为底；<code>x</code>必须是正数</td>
        </tr>
        <tr>
            <td><code>log10(x)</code></td>
            <td>以10为底的对数</td>
        </tr>
    </tbody>
</table>

<p>针对<code>complex</code>（§14.4）的版本在<code>&lt;complex&gt;</code>中。
以上函数的返回值类型与参数相同。</p>
<p>错误报告的方式是将<code>errno</code>设置为<code>&lt;cerrno&gt;</code>中的值，
定义域超出范围设为<code>EDOM</code>，值域超出范围设为<code>ERANGE</code>。例如：</p>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">f</span><span class="hljs-params">()</span>
</span>{
    errno = <span class="hljs-number">0</span>; <span class="hljs-comment">// 清除错误状态</span>
    <span class="hljs-built_in">sqrt</span>(<span class="hljs-number">-1</span>);
    <span class="hljs-keyword">if</span> (errno==EDOM)
        cerr &lt;&lt; <span class="hljs-string">&quot;sqrt() not defined for negative argument&quot;</span>;

    errno = <span class="hljs-number">0</span>; <span class="hljs-comment">// 清除错误状态</span>
    <span class="hljs-built_in">pow</span>(numeric_limits&lt;<span class="hljs-type">double</span>&gt;::<span class="hljs-built_in">max</span>(),<span class="hljs-number">2</span>);
    <span class="hljs-keyword">if</span> (errno == ERANGE)
        cerr &lt;&lt; <span class="hljs-string">&quot;result of pow() too large to represent as a double&quot;</span>;
}
</code></pre>
<p>有些被称为<em>特殊数学函数（special mathematical functions）</em>
的数学函数在<code>&lt;cstdlib&gt;</code>里，
还有几个在<code>&lt;cmath&gt;</code>比如 <code>beta()</code>、<code>rieman_zeta()</code>、<code>sph_bessel()</code>。</p>
<p><a class="en-page-number" id="189"></a></p>
<h2 id="14.3">14.3 数值算法 </h2>
<p><code>&lt;numeric&gt;</code>里有几个泛化过的数值算法，比如<code>accumulate()</code>。</p>
<table style="width:90%;margin-left:auto;margin-right:auto;">
    <tbody>
        <tr>
            <th colspan="2" style="text-align: center">
                <strong>数值算法</strong><br>
            </th>
        </tr>
        <tr>
            <td style="width:10%"><code>x=accumulate(b,e,i)</code></td>
            <td><code>x</code>是<code>i</code>与[<code>b</code>:<code>e</code>)间元素的和</td>
        </tr>
        <tr>
            <td><code>x=accumulate(b,e,i,f)</code></td>
            <td>调用<code>accumulate</code>时用<code>f</code>替换<code>+</code></td>
        </tr>
        <tr>
            <td><code>x=inner_product(b,e,b2,i)</code></td>
            <td>
                <code>x</code>是[<code>b</code>:<code>e</code>)与
                [<code>b2</code>:<code>b2+(e-b)</code>)的内积，
                即<code>i</code>与<code>(*p1)*(*p2)</code>的和，
                其中<code>p1</code>是[<code>b</code>:<code>e</code>)
                中的元素，且对应来自[<code>b2</code>:<code>b2+(e-b)</code>)
                中的元素<code>p2</code>
            </td>
        </tr>
        <tr>
            <td><code>x=inner_product(b,e,b2,i,f,f2)</code></td>
            <td>调用<code>inner_product</code>时用<code>f</code>
            和<code>f2</code>分别替换<code>+</code>和<code>*</code></td>
        </tr>
        <tr>
            <td><code>p=partial_sum(b,e,out)</code></td>
            <td>
                [<code>out</code>:<code>p</code>)的第<code>i</code>个元素是
                [<code>b</code>:<code>b+i</code>]间所有元素的和
            </td>
        </tr>
        <tr>
            <td><code>p=partial_sum(b,e,out,f)</code></td>
            <td>
                调用<code>partial_sum</code>时以<code>f</code>替换<code>+</code>
            </td>
        </tr>
        <tr>
            <td><code>p=adjacent_difference(b,e,out)</code></td>
            <td>
                <code>i&gt;0</code>时，[<code>out</code>:<code>p</code>)
                的第<code>i</code>个元素是<code>*(b+i)-*(b+i-1)</code>；
                <code>e-b&gt;0</code>时，<code>*out</code>就是<code>*b</code>
            </td>
        </tr>
        <tr>
            <td><code>p=adjacent_difference(b,e,out,f)</code></td>
            <td>
                调用<code>adjacent_difference</code>时以
                <code>f</code>替换<code>-</code>
            </td>
        </tr>
        <tr>
            <td><code>iota(b,e,v)</code></td>
            <td>
                把<code>++v</code>依次赋值给[<code>b</code>:<code>e</code>)
                之间的元素，因此元素序列就变成<code>v+1</code>,<code>v+2</code>,……
            </td>
        </tr>
        <tr>
            <td><code>x=gcd(n,m)</code></td>
            <td><code>x</code>是整数<code>n</code>和<code>m</code>的最大公约数</td>
        </tr>
        <tr>
            <td><code>x=lcm(n,m)</code></td>
            <td><code>x</code>是整数<code>n</code>和<code>m</code>的最小公倍数</td>
        </tr>
    </tbody>
</table>

<p>这些算法泛化了常见运算，比如求和运算被应用到所有类型的元素序列上了。
也把应用在元素序列上的操作参数化了。
对于每个算法，最常规的版本是将常规运算代入到通用版本得到的。例如：</p>
<pre><code class="lang-cpp">list&lt;<span class="hljs-type">double</span>&gt; lst {<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>, <span class="hljs-number">9999.99999</span>};
<span class="hljs-keyword">auto</span> s = <span class="hljs-built_in">accumulate</span>(lst.<span class="hljs-built_in">begin</span>(),lst.<span class="hljs-built_in">end</span>(),<span class="hljs-number">0.0</span>); <span class="hljs-comment">// 求和得到：10014.9999</span>
</code></pre>
<p>这些算法适用于标准库中的所有元素序列，可以将操作以参数的形式传入
<span title="我有点疑惑，此处就是 §14.3，这个参考提示意义何在？——译者">（§14.3）</span>。</p>
<h3 id="14.3.1">14.3.1 并行算法 </h3>
<p><code>&lt;numeric&gt;</code>中，数值算法具有略带差异的并行版本（§12.9）：</p>
<table style="width:90%;margin-left:auto;margin-right:auto;">
    <tbody>
        <tr>
            <th colspan="2" style="text-align: center">
                <strong>并行数值算法</strong><br>
            </th>
        </tr>
        <tr>
            <td style="width:30%"><code>x=reduce(b,e,v)</code></td>
            <td>无序执行的<code>x=accumulate(b,e,v)</code></td>
        </tr>
        <tr>
            <td><code>x=reduce(b,e)</code></td>
            <td><code>x=reduce(b,e,V{})</code>，其中<code>V</code>
            是<code>b</code>的值类型</td>
        </tr>
        <tr>
            <td><code>x=reduce(pol,b,e,v)</code></td>
            <td>采用执行策略<code>pol</code>的
            <code>x=reduce(b,e,v)</code></td>
        </tr>
        <tr>
            <td><code>x=reduce(pol,b,e)</code></td>
            <td><code>x=reduce(pol,b,e,V{})</code>，其中<code>V</code>
            是<code>b</code>的值类型</td>
        </tr>
        <tr>
            <td><code>p=exclusive_scan(pol,b,e,out)</code></td>
            <td>按照<code>pol</code>策略执行
            <code>p=partial_sum(b,e,out)</code>
            计算第i个和的时候，第i个输入元素不参与计算</td>
        </tr>
        <tr>
            <td><code>p=inclusive_scan(pol,b,e,out)</code></td>
            <td>按照<code>pol</code>策略执行
            <code>p=partial_sum(b,e,out)</code>
            计算第i个和的时候，第i个输入元素参与计算</td>
        </tr>
    </tbody>
</table>

<p><a class="en-page-number" id="190"></a></p>
<table style="width:90%;margin-left:auto;margin-right:auto;">
    <tbody>
        <tr>
            <th colspan="2" style="text-align: center">
                <strong>并行数值算法（续表）</strong><br>
            </th>
        </tr>
        <tr>
            <td style="width:30%"><code>p=transform_reduce(pol,b,e,f,v)</code></td>
            <td>对[<code>b</code>:<code>e</code>)中的每个
            <code>x</code>执行<code>f(x)</code>，
            而后执行<code>reduce</code></td>
        </tr>
        <tr>
            <td><code>p=transform_exclusive_scan(pol,b,e,out,f,v)</code></td>
            <td>对[<code>b</code>:<code>e</code>)中的每个
            <code>x</code>执行<code>f(x)</code>，
            而后执行<code>exclusive_scan</code></td>
        </tr>
        <tr>
            <td><code>p=transform_inclusive_scan(pol,b,e,f,v)</code></td>
            <td>对[<code>b</code>:<code>e</code>)中的每个
            <code>x</code>执行<code>f(x)</code>，
            而后执行<code>inclusive_scan</code></td>
        </tr>
    </tbody>
</table>

<p>为简化叙述，此处没有提及那些采用仿函数参数替代<code>+</code>和<code>=</code>算法版本。
除<code>reduce()</code>意外，采用默认（顺序）执行策略和缺省值的版本也未提及。</p>
<p>此处的算法和<code>&lt;algorithm&gt;</code>里的并行算法一样，可以指定执行策略：</p>
<pre><code class="lang-cpp">vector&lt;<span class="hljs-type">double</span>&gt; v {<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>, <span class="hljs-number">9999.99999</span>};
<span class="hljs-keyword">auto</span> s = <span class="hljs-built_in">reduce</span>(v.<span class="hljs-built_in">begin</span>(),v.<span class="hljs-built_in">end</span>());     <span class="hljs-comment">// 以double的默认值为初值累加求和</span>

vector&lt;<span class="hljs-type">double</span>&gt; large;
<span class="hljs-comment">// ... 以大量的值填充large ...</span>
<span class="hljs-keyword">auto</span> s2 = <span class="hljs-built_in">reduce</span>(par_unseq,large.<span class="hljs-built_in">begin</span>(),large.<span class="hljs-built_in">end</span>());  <span class="hljs-comment">// 求和，并行策略可用则用，不可用就顺序执行</span>
</code></pre>
<p>（<code>reduce()</code>之类的）并行算法区别于顺序版本（即<code>accumulate()</code>）之处在于：
并行算法中针对元素的操作执行顺序不定。</p>
<h2 id="14.4">14.4 复数 </h2>
<p>标准库提供了一系列的复数类型，它们符合§4.2.1中<code>complex</code>的描述。
为了让其中的标量能支持单精度浮点数（<code>float</code>）、双精度浮点数（<code>double</code>）等类型，
标准库的<code>complex</code>是个模板：</p>
<pre><code class="lang-cpp"><span class="hljs-keyword">template</span>&lt;<span class="hljs-keyword">typename</span> Scalar&gt;
<span class="hljs-keyword">class</span> <span class="hljs-title class_">complex</span> {
<span class="hljs-keyword">public</span>:
    <span class="hljs-built_in">complex</span>(<span class="hljs-type">const</span> Scalar&amp; re ={}, <span class="hljs-type">const</span> Scalar&amp; im ={});    <span class="hljs-comment">// 函数参数缺省值；参见 §3.6.1</span>
    <span class="hljs-comment">// ...</span>
};
</code></pre>
<p>复数支持常见的算术操作和大多数的数学函数。例如：</p>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">f</span><span class="hljs-params">(complex&lt;<span class="hljs-type">float</span>&gt; fl, complex&lt;<span class="hljs-type">double</span>&gt; db)</span>
</span>{
    complex&lt;<span class="hljs-type">long</span> <span class="hljs-type">double</span>&gt; ld {fl+<span class="hljs-built_in">sqrt</span>(db)};
    db += fl*<span class="hljs-number">3</span>;
    fl = <span class="hljs-built_in">pow</span>(<span class="hljs-number">1</span>/fl,<span class="hljs-number">2</span>);
    <span class="hljs-comment">// ...</span>
}
</code></pre>
<p><code>sqrt()</code>和<code>pow()</code>（幂运算）属于<code>&lt;complex&gt;</code>中定义的常见数学函数。</p>
<p><a class="en-page-number" id="191"></a></p>
<h2 id="14.5">14.5 随机数 </h2>
<p>许多领域需要随机数，比如测试、游戏、仿真以及安全系统。
标准库在<code>&lt;random&gt;</code>中提供了种类繁多的随机数发生器，它们反映了应用领域的多样性。
随机数发生器由两部分组成：</p>
<ul>
<li>[1] <em>引擎（engine）</em>，负责生成随机值或伪随机值的序列</li>
<li>[2] <em>分布器（distribution）</em>，负责将这些值映射到特定的数学分布</li>
</ul>
<p>分布器的例子有：<code>uniform_int_distribution</code>（生成所有可能值的概率相同）、
<code>normal_distribution</code>（正态分布，即“铃铛曲线”）、
<code>exponential_distribution</code>（指数分布）；它们都可以指定生成的随机数范围。
例如：</p>
<pre><code class="lang-cpp"><span class="hljs-keyword">using</span> my_engine = default_random_engine;            <span class="hljs-comment">// 引擎类型</span>
<span class="hljs-keyword">using</span> my_distribution = uniform_int_distribution&lt;&gt;; <span class="hljs-comment">// 分布器类型</span>

my_engine re {};                                    <span class="hljs-comment">// 默认引擎</span>
my_distribution one_to_six {<span class="hljs-number">1</span>,<span class="hljs-number">6</span>};                   <span class="hljs-comment">// 映射到整数 1..6 的分布器</span>
<span class="hljs-keyword">auto</span> die = [](){ <span class="hljs-keyword">return</span> <span class="hljs-built_in">one_to_six</span>(re); }           <span class="hljs-comment">// 创建一个随机数生成器</span>

<span class="hljs-type">int</span> x = <span class="hljs-built_in">die</span>();                                      <span class="hljs-comment">// 掷骰子：x的值在闭区间[1:6]内</span>
</code></pre>
<p>出于对标准库中随机数组件通用性和性能的持续关注，
一位专家称其为“每个随机数程序库成长的榜样”。
但是要论“新手之友”的称号，它可就愧不敢当了。
前述代码示例借助<code>using</code>语句和lambda表达式，稍稍提升了一点代码可读性。</p>
<p>对于（任何背景的）新手而言，随机数程序库那个完整的通用接口绝对是个大坑。
一个简洁统一的随机数生成器往往就足以起步了。例如：</p>
<pre><code class="lang-cpp">Rand_int rnd {<span class="hljs-number">1</span>,<span class="hljs-number">10</span>};    <span class="hljs-comment">// 创建一个[1:10]之间的随机数生成器</span>
<span class="hljs-type">int</span> x = <span class="hljs-built_in">rnd</span>();          <span class="hljs-comment">// x是闭区间[1:10]内的一个值</span>
</code></pre>
<p>但到哪儿去找这个东西呢？我们得弄个跟<code>die()</code>差不多的东西，
把引擎和分布器撮合起来，装进一个<code>Rand_int</code>类：</p>
<pre><code class="lang-cpp"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Rand_int</span> {
<span class="hljs-keyword">public</span>:
    <span class="hljs-built_in">Rand_int</span>(<span class="hljs-type">int</span> low, <span class="hljs-type">int</span> high) :dist{low,high} { }
    <span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">operator</span><span class="hljs-params">()</span><span class="hljs-params">()</span> </span>{ <span class="hljs-keyword">return</span> <span class="hljs-built_in">dist</span>(re); }       <span class="hljs-comment">// 抽一个 int</span>
    <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">seed</span><span class="hljs-params">(<span class="hljs-type">int</span> s)</span> </span>{ re.<span class="hljs-built_in">seed</span>(s); }            <span class="hljs-comment">// 设置新的随机数引擎种子</span>
<span class="hljs-keyword">private</span>:
    default_random_engine re;
    uniform_int_distribution&lt;&gt; dist;
};
</code></pre>
<p>这个定义仍然是“专家级”的，但是<code>Rand_int()</code>的<em>使用</em>，
学习C++第一周的新手就可以轻松掌握了。例如：</p>
<p><a class="en-page-number" id="192"></a></p>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span>
</span>{
    <span class="hljs-keyword">constexpr</span> <span class="hljs-type">int</span> max = <span class="hljs-number">9</span>;
    Rand_int rnd {<span class="hljs-number">0</span>,max};           <span class="hljs-comment">// 创建一个统一的随机数生成器</span>

    <span class="hljs-function">vector&lt;<span class="hljs-type">int</span>&gt; <span class="hljs-title">histogram</span><span class="hljs-params">(max+<span class="hljs-number">1</span>)</span></span>;   <span class="hljs-comment">// 创建一个容量合适的vector</span>
    <span class="hljs-keyword">for</span> (<span class="hljs-type">int</span> i=<span class="hljs-number">0</span>; i!=<span class="hljs-number">200</span>; ++i)
        ++histogram[<span class="hljs-built_in">rnd</span>()];         <span class="hljs-comment">// 以[0:max]之间的数字作为频率填充直方图</span>

    <span class="hljs-keyword">for</span> (<span class="hljs-type">int</span> i = <span class="hljs-number">0</span>; i!=histogram.<span class="hljs-built_in">size</span>(); ++i) { <span class="hljs-comment">// 绘制柱状图</span>
        cout &lt;&lt; i &lt;&lt; <span class="hljs-string">&apos;\t&apos;</span>;
        <span class="hljs-keyword">for</span> (<span class="hljs-type">int</span> j=<span class="hljs-number">0</span>; j!=histogram[i]; ++j) cout &lt;&lt; <span class="hljs-string">&apos;*&apos;</span>;
        cout &lt;&lt; endl;
    }
}
</code></pre>
<p>输出是个（索然无味的）均匀分布（具有合理的统计波动）。</p>
<pre><code class="lang-cpp"><span class="hljs-number">0</span>   *********************
<span class="hljs-number">1</span>   ****************
<span class="hljs-number">2</span>   *******************
<span class="hljs-number">3</span>   ********************
<span class="hljs-number">4</span>   ****************
<span class="hljs-number">5</span>   ***********************
<span class="hljs-number">6</span>   **************************
<span class="hljs-number">7</span>   ***********
<span class="hljs-number">8</span>   **********************
<span class="hljs-number">9</span>   *************************
</code></pre>
<p>C++没有标准的图形库，所以这里用了“ASCII图形”。
毫无疑问，C++有众多开源以及商业的图形和GUI库，
但我在本书中限定自己仅使用ISO标准的构件。</p>
<h2 id="14.6">14.6 矢量算术 </h2>
<p>§11.2叙述的<code>vector</code>设计目的是作为一个承载值的通用机制，
要灵活，并且能融入容器、迭代器、算法这套架构。
可惜它不支持数学矢量（vector）的运算。
给<code>vector</code>添加这些运算没什么难度，
但它的通用性和灵活性跟繁重的数值作业所需的优化格格不入。
因此，标准库（在<code>&lt;valarray&gt;</code>中）提供了一个类似<code>vector</code>的模板，
被称为<code>valarray</code>，它的通用性不济，但在数值计算所需的优化方面却精益求精：</p>
<pre><code class="lang-cpp"><span class="hljs-keyword">template</span>&lt;<span class="hljs-keyword">typename</span> T&gt;
<span class="hljs-keyword">class</span> <span class="hljs-title class_">valarray</span> {
    <span class="hljs-comment">// ...</span>
};
</code></pre>
<p><code>valarray</code>支持常见的算术运算和大多数的数学函数，例如：</p>
<p><a class="en-page-number" id="193"></a></p>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">f</span><span class="hljs-params">(valarray&lt;<span class="hljs-type">double</span>&gt;&amp; a1, valarray&lt;<span class="hljs-type">double</span>&gt;&amp; a2)</span>
</span>{
    valarray&lt;<span class="hljs-type">double</span>&gt; a = a1*<span class="hljs-number">3.14</span>+a2/a1;         <span class="hljs-comment">// 数值数组运算符 *、+、/、和=</span>
    a2 += a1*<span class="hljs-number">3.14</span>;
    a = <span class="hljs-built_in">abs</span>(a);
    <span class="hljs-type">double</span> d = a2[<span class="hljs-number">7</span>];
    <span class="hljs-comment">// ...</span>
}
</code></pre>
<p>除算术运算之外，<code>valarray</code>还支持跨步访问，以辅助多维计算的实现。</p>
<h2 id="14.7">14.7 数值范围 </h2>
<p>标准库在<code>&lt;limits&gt;</code>中提供了一些类，用于描述内建类型的属性——
比如<code>float</code>指数部分的最大值，或者每个<code>int</code>的字节数。
比如说，可以断言<code>char</code>是有符号的：</p>
<pre><code class="lang-cpp"><span class="hljs-built_in">static_assert</span>(numeric_limits&lt;<span class="hljs-type">char</span>&gt;::is_signed,<span class="hljs-string">&quot;unsigned characters!&quot;</span>);
<span class="hljs-built_in">static_assert</span>(<span class="hljs-number">100000</span>&lt;numeric_limits&lt;<span class="hljs-type">int</span>&gt;::<span class="hljs-built_in">max</span>(),<span class="hljs-string">&quot;small ints!&quot;</span>);
</code></pre>
<p>请留意，第二个断言能够运行的原因，来（且仅来）自于
<code>numeric_limits&lt;int&gt;::max()</code>是个<code>constexpr</code>函数（§1.6）这一事实。</p>
<h2 id="14.8">14.8 忠告 </h2>
<ul>
<li>[1] 数值计算问题通常很微妙，如果对这类问题的某一方面没有100%的确信，
  要么尝试咨询专家建议，要么实践检验，或者干脆双管齐下；§14.1。</li>
<li>[2] 别把繁重的数值计算建立在编程语言的基础构件上，请采用程序库；§14.1。</li>
<li>[3] 如果要从序列里计算出一个值，尝试写循环之前，请先考虑<code>accumulate()</code>、
  <code>inner_product()</code>、<code>partial_sum()</code>、<code>adjacent_difference()</code>
  ；§14.3。</li>
<li>[4] 为复数运算采用<code>std::complex</code>；§14.4。</li>
<li>[5] 把随机数引擎和一个分布器组合起来创建随机数生成器；§14.5。</li>
<li>[6] 确保你的随机数足够随机；§14.5。</li>
<li>[7] 别用C标准库的<code>rand()</code>；对于实际应用而言，它的随机度不够；§14.5。</li>
<li>[8] 如果运行时的效率压倒操作和元素类型方面的灵活性，
  请为数值计算采用<code>valarray</code>；§14.6。</li>
<li>[9] 数值类型的属性可以通过<code>numeric_limits</code>获取；§14.7。</li>
<li>[10] 请使用<code>numeric_limits</code>查询数值类型的属性，确保它们够用；§14.7。</li>
</ul>
<blockquote id="fn_1">
<sup>1</sup>. 这段话刊载于 R. W. Hamming 的著作《Numerical methods for scientists and engineers》，此书未见中文版。—— 译者注<a href="#reffn_1" title="Jump back to footnote [1] in the text."> ↩</a>
</blockquote>
<blockquote id="fn_2">
<sup>2</sup>. Anthony Ralston 简介见 <a href="https://history.computer.org/pioneers/ralston.html" target="_blank">https://history.computer.org/pioneers/ralston.html</a> —— 译者注<a href="#reffn_2" title="Jump back to footnote [2] in the text."> ↩</a>
</blockquote>

<script>console.log(window.location.pathname)</script>
<div id="disqus_thread"></div>
<script>

/**
*  RECOMMENDED CONFIGURATION VARIABLES: EDIT AND UNCOMMENT THE SECTION BELOW TO INSERT DYNAMIC VALUES FROM YOUR PLATFORM OR CMS.
*  LEARN WHY DEFINING THESE VARIABLES IS IMPORTANT: https://disqus.com/admin/universalcode/#configuration-variables*/
/*
var disqus_config = function () {
this.page.url = window.location.href;
this.page.identifier = window.location.pathname;
};
*/
(function() { // DON'T EDIT BELOW THIS LINE
var d = document, s = d.createElement('script');
s.src = 'https://a-tour-of-cpp-2nd-cn.disqus.com/embed.js';
s.setAttribute('data-timestamp', +new Date());
(d.head || d.body).appendChild(s);
})();
</script>
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" target="_blank">comments powered by Disqus.</a></noscript>
                                
    

                                </section>
                            
    </div>
    <div class="search-results">
        <div class="has-results">
            
            <h1 class="search-results-title"><span class='search-results-count'></span> results matching "<span class='search-query'></span>"</h1>
            <ul class="search-results-list"></ul>
            
        </div>
        <div class="no-results">
            
            <h1 class="search-results-title">No results matching "<span class='search-query'></span>"</h1>
            
        </div>
    </div>
</div>

                        </div>
                    </div>
                
            </div>

            
                
                <a href="ch13.html" class="navigation navigation-prev " aria-label="Previous page: 13 实用功能">
                    <i class="fa fa-angle-left"></i>
                </a>
                
                
                <a href="ch15.html" class="navigation navigation-next " aria-label="Next page: 15 并发">
                    <i class="fa fa-angle-right"></i>
                </a>
                
            
        
    </div>

    <script>
        var gitbook = gitbook || [];
        gitbook.push(function() {
            gitbook.page.hasChanged({"page":{"ch":14,"title":"14 数值","level":"1.16","depth":1,"next":{"title":"15 并发","level":"1.17","depth":1,"path":"ch15.md","ref":"ch15.md","articles":[]},"previous":{"title":"13 实用功能","level":"1.15","depth":1,"path":"ch13.md","ref":"ch13.md","articles":[]},"dir":"ltr"},"config":{"plugins":["@dogatana/page-toc-button","@dogatana/back-to-top-button","copy-code-button","forkmegithub","disqus-legacy"],"root":"./src","styles":{"website":"styles/website.css","pdf":"styles/pdf.css","epub":"styles/epub.css","mobi":"styles/mobi.css","ebook":"styles/ebook.css","print":"styles/print.css"},"pluginsConfig":{"@dogatana/back-to-top-button":{},"styles":{"website":"styles/website.css"},"search":{},"@dogatana/page-toc-button":{},"lunr":{"maxIndexSize":1000000,"ignoreSpecialCharacters":false},"fontsettings":{"theme":"white","family":"sans","size":2},"highlight":{},"disqus-legacy":{"shortname":"a-tour-of-cpp-2nd-cn"},"copy-code-button":{},"forkmegithub":{"color":"orange","url":"https://github.com/windsting/a-tour-of-cpp-2nd-cn"},"theme-default":{"styles":{"website":"styles/website.css","pdf":"styles/pdf.css","epub":"styles/epub.css","mobi":"styles/mobi.css","ebook":"styles/ebook.css","print":"styles/print.css"},"showLevel":false}},"theme":"default","author":"Windsting","pdf":{"pageNumbers":true,"fontSize":14,"fontFamily":"Arial","paperSize":"a5","chapterMark":"pagebreak","pageBreaksBefore":"/","margin":{"right":62,"left":62,"top":56,"bottom":56},"embedFonts":false},"structure":{"langs":"LANGS.md","readme":"README.md","glossary":"GLOSSARY.md","summary":"SUMMARY.md"},"variables":{},"title":"C++导览 第二版 简体中文版","language":"zh-hans","links":{"sidebar":{"Github Link":"https://github.com/windsting/a-tour-of-cpp-2nd-cn"}},"gitbook":"*","description":"A Tour of C++ (第二版) 非官方中译本"},"file":{"path":"ch14.md","mtime":"2023-02-12T09:23:08.793Z","type":"markdown"},"gitbook":{"version":"5.1.1","time":"2023-10-27T09:54:29.738Z"},"basePath":".","book":{"language":""}});
        });
    </script>
</div>

        
    <noscript>
        <style>
            .honkit-cloak {
                display: block !important;
            }
        </style>
    </noscript>
    <script>
        // Restore sidebar state as critical path for prevent layout shift
        function __init__getSidebarState(defaultValue){
            var baseKey = "";
            var key = baseKey + ":sidebar";
            try {
                var value = localStorage[key];
                if (value === undefined) {
                    return defaultValue;
                }
                var parsed = JSON.parse(value);
                return parsed == null ? defaultValue : parsed;
            } catch (e) {
                return defaultValue;
            }
        }
        function __init__restoreLastSidebarState() {
            var isMobile = window.matchMedia("(max-width: 600px)").matches;
            if (isMobile) {
                // Init last state if not mobile
                return;
            }
            var sidebarState = __init__getSidebarState(true);
            var book = document.querySelector(".book");
            // Show sidebar if it enabled
            if (sidebarState && book) {
                book.classList.add("without-animation", "with-summary");
            }
        }

        try {
            __init__restoreLastSidebarState();
        } finally {
            var book = document.querySelector(".book");
            book.classList.remove("honkit-cloak");
        }
    </script>
    <script src="gitbook/gitbook.js"></script>
    <script src="gitbook/theme.js"></script>
    
        
        <script src="gitbook/@dogatana/honkit-plugin-page-toc-button/plugin.js"></script>
        
    
        
        <script src="gitbook/@dogatana/honkit-plugin-back-to-top-button/plugin.js"></script>
        
    
        
        <script src="gitbook/gitbook-plugin-copy-code-button/toggle.js"></script>
        
    
        
        <script src="gitbook/gitbook-plugin-forkmegithub/plugin.js"></script>
        
    
        
        <script src="gitbook/gitbook-plugin-search/search-engine.js"></script>
        
    
        
        <script src="gitbook/gitbook-plugin-search/search.js"></script>
        
    
        
        <script src="gitbook/gitbook-plugin-lunr/lunr.min.js"></script>
        
    
        
        <script src="gitbook/gitbook-plugin-lunr/search-lunr.js"></script>
        
    
        
        <script src="gitbook/gitbook-plugin-fontsettings/fontsettings.js"></script>
        
    

    </body>
</html>

